function mgr:on_cxx_completion(doc, status, helper)
	-- C++ 自动补全
	-- status 
	-- 0 popup
	-- 1 commit
	-- 2 typing
	-- 3 dismiss completion list
	-- 4 dismiss completion tip
	-- 5 item selected

	-- print( "complete ", status );
	if status == 3 or status == 4 then
        return 1;
    end ;
    -- 得到当前行
    local text = doc.get_text(doc.cursor_line, 0, doc.cursor_column);
    if text == nil then
        text = "";
    end ;

    if self.__last_cmd[0] == _op.completion_typing
            and self.__last_cmd[1] == _op.backspace_character
            and text:match("([^ \t]+)") == nil
    then
		-- 行内容删空后,自动关闭补全
		helper.cancel_completion();
		lsp:cleanup_completion(doc);
        return 0;
    end;
	-- print( "complete ", status, " :", text );
	if doc.cursor_line <= 10 and text:match("^%s*//.*$") ~= nil  then
		if status == 0 then
			lsp:cleanup_completion(doc);
			helper.clear(false);
			local pp_icon = 0;
			if text:match("^%s*//%s*toolset:.*$") ~= nil then
				for i, toolset in ipairs(TOOLSETS) do
					helper.push_back(toolset.name, pp_icon, 0xFFF0);
				end ;
				status = 2;
			elseif text:match("^%s*//%s*[^:]*$") ~= nil then
				helper.push_back("toolset", pp_icon, 0xFFF1);
				helper.push_back("lib", pp_icon, 0xFFF1);
				helper.push_back("lib_path", pp_icon, 0xFFF1);
				helper.push_back("include", pp_icon, 0xFFF1);
				helper.push_back("flags", pp_icon, 0xFFF1);
				helper.push_back("ld_flags", pp_icon, 0xFFF1);
				helper.push_back("args", pp_icon, 0xFFF1);
				helper.push_back("cwd", pp_icon, 0xFFF1);
				helper.push_back("env", pp_icon, 0xFFF1);
				status = 2;
			else
				helper.cancel_completion();
				return 0;
			end;
		elseif status == 1 then
			local text = doc.get_text(doc.cursor_line, 0, 2000);
			local selected_text = helper.selected_item_text;
			local selected_item_type = helper.selected_item_data;
			if selected_item_type == 0xFFF0 then
				local parts = {text:match("^(%s*//%s*toolset%s*:%s*)(.*)$")};
				doc.select_text(doc.cursor_line, sizeof(parts[1]), doc.cursor_line, sizeof(parts[1]..parts[2]));
				doc.set_text(selected_text);
			elseif selected_item_type == 0xFFF1 then
				local parts = {text:match("^(%s*//%s*)([^:]*:?)(.*)$")};
				doc.select_text(doc.cursor_line, sizeof(parts[1]), doc.cursor_line, sizeof(parts[1]..parts[2]));
				doc.set_text(selected_text..":");
			end;
			helper.cancel_completion();
			lsp:cleanup_completion(doc);
			return 0;
		elseif status == 5 then
			return 1;
		end;
	elseif text:match("^%s*#%s*include%s+[\"<].-$") ~= nil then
		-- 自动补全include, 编辑器内置功能
		lsp:cleanup_completion(doc);
        return 0;
	elseif text:match("^%s*#%s*include%s+$") ~= nil then
        -- 自动补全include 关闭
        helper.cancel_completion();
		return 0;
	elseif text:match("^%s*#.*$") ~= nil then
		if text:match("^%s*#%w+%s+.*$") ~= nil then
			-- complete preprocessor arguments with LSP
		elseif status == 0 then
			-- 自动补全预处理符号
			lsp:cleanup_completion(doc);
			helper.clear(false);
			local pp_icon = icon("preprocessor");
			helper.push_back("include", pp_icon, 0);
			helper.push_back("if", pp_icon, 0);
			helper.push_back("ifdef", pp_icon, 0);
			helper.push_back("ifndef", pp_icon, 0);
			helper.push_back("line", pp_icon, 0);
			helper.push_back("else", pp_icon, 0);
			helper.push_back("elif", pp_icon, 0);
			helper.push_back("endif", pp_icon, 0);
			helper.push_back("define", pp_icon, 0);
			helper.push_back("undef", pp_icon, 0);
			helper.push_back("pragma", pp_icon, 0);
			helper.push_back("error", pp_icon, 0);
			helper.push_back("warning", pp_icon, 0);
			status = 2;
		elseif status == 5 then
			return 1;
		end;
	end;

	if status == 5 then
		lsp:update_completion_tip(doc, helper);
		return 1;
	end;

    -- 取得最后一部分
    local last_text = text:match(".-(%.[~_%w]*)$");
    if last_text == nil then
        last_text = text:match(".-(::[~_%w]*)$");
    end ;
    if last_text == nil then
        last_text = text:match(".-(%->[~_%w]*)$");
    end ;
    if last_text ~= nil then
        text = last_text;
    end ;

    local context = text:match(".-%.([~_%w]*)$");
    if context == nil then
        context = text:match(".-::([~_%w]*)$");
    end ;
    if context == nil then
        context = text:match(".-%->([~_%w]*)$");
    end ;
    if context == nil then
        context = text:match(".-([~_%w]+)$");
    end ;
    if context == nil then
        context = "";
    end ;
	-- print( "context ", context, " text ", text );

	if status == 1 then
		if lsp:commit_completion(doc, helper) then
			return 1;
		end;
        -- 选择当前项
        local offset = 0;
        while true do
            local c = doc.get_text(doc.cursor_line, doc.cursor_column + offset, 1);
			if c:match("^([#_%w])$") == nil then
                break ;
            end ;
            offset = offset + 1;
        end ;
        doc.select_text(doc.cursor_line, doc.cursor_column - sizeof(context), doc.cursor_line, doc.cursor_column + offset);
        local selected_text = helper.selected_item_text;
		local selected_icon = helper.selected_item_icon;
		local namespace_icon = icon("namespace");
		local method_icon = icon("method");
		local pp_icon = icon("preprocessor");
		local update_completion_list = false;
        if selected_text == "dynamic_cast"
                or selected_text == "static_cast"
                or selected_text == "reinterpret_cast"
                or selected_text == "const_cast"
        then
            -- c++ cast自动加'<'
            if doc.get_text(doc.cursor_line, doc.cursor_column + offset, 1) == "<" then
                doc.select_text(doc.cursor_line, doc.cursor_column - sizeof(context), doc.cursor_line, doc.cursor_column + offset + 1);
            end ;
			selected_text = selected_text .. "<";
		elseif namespace_icon == selected_icon then
			selected_text = selected_text .. "::";
			update_completion_list = true;
		elseif pp_icon == selected_icon then
			if doc.cursor_line == 0 and selected_text == "ifndef" then
				local file_name = doc.file_name;
				file_name = file_name:match("^.*\\(.+)");
				file_name = file_name:upper();
				file_name = file_name:gsub("[-=+%.]","_");
				file_name = [[__]]..file_name..[[_]]..os.date([[%Y_%m_%d]])..[[__]];
				doc.replace(selected_text.." ", false);
				selected_text = file_name .. "\n#define " .. file_name .. "\n\n";
				doc.replace(selected_text, false);
				doc.set_cursor(0x7FFFFFFF, 0x7FFFFFFF);
				doc.replace("\n#endif // " .. file_name .. "\n", false);
				doc.set_cursor(2, 0);
				doc.center_cursor_line();

				helper.cancel_completion();
				lsp:cleanup_completion(doc);
				return 1;
			elseif selected_text ~= "else" and selected_text ~= "endif" then
				selected_text = selected_text .. " ";
			end;
		elseif method_icon == selected_icon then
			-- selected_text = selected_text .. "(";
		end ;
		doc.set_text(selected_text);
		if update_completion_list then
			edx.do_cmd(_op.update_completion_list);
		else
			helper.cancel_completion();
			lsp:cleanup_completion(doc);
		end;
        return 1;
    end ;
	if status == 0 then
		lsp:do_completion(doc, helper);
		return 1;
    end;
    if status == 2 then
        do
            -- 添加光标后内容, 以实现整词选择
            local offset = 0;
            while true do
                local c = doc.get_text(doc.cursor_line, doc.cursor_column + offset, 1);
                if c:match("^([_%w])$") == nil then
                    break ;
                end ;
                offset = offset + 1;
                context = context .. c;
            end ;
        end ;
        helper.select_item(context);
        helper.redraw();
        return 1;
    end ;
    return 0;
end;
